package com.alibaba.ttl.threadpool;

import cn.micro.ttl.mdc.MDCThreadWrap;
import com.alibaba.ttl.TtlCallable;
import com.alibaba.ttl.TtlRunnable;
import com.alibaba.ttl.spi.TtlEnhanced;
import com.alibaba.ttl.spi.TtlWrapper;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.*;

public class ScheduledExecutorServiceTtlMDCWrapper implements ScheduledExecutorService, TtlWrapper<ScheduledExecutorService>, TtlEnhanced {

    private final ScheduledExecutorService scheduledExecutorService;
    protected final boolean idempotent;

    public ScheduledExecutorServiceTtlMDCWrapper(ScheduledExecutorService scheduledExecutorService, boolean idempotent) {
        this.scheduledExecutorService = scheduledExecutorService;
        this.idempotent = idempotent;
    }

    @Override
    public void execute(Runnable command) {
        scheduledExecutorService.execute(TtlRunnable.get(MDCThreadWrap.runnable(command), false, idempotent));
    }

    @Override
    public ScheduledExecutorService unwrap() {
        return scheduledExecutorService;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        ScheduledExecutorServiceTtlMDCWrapper that = (ScheduledExecutorServiceTtlMDCWrapper) o;

        return scheduledExecutorService.equals(that.scheduledExecutorService);
    }

    @Override
    public int hashCode() {
        return scheduledExecutorService.hashCode();
    }

    @Override
    public String toString() {
        return this.getClass().getName() + " - " + scheduledExecutorService.toString();
    }

    @Override
    public void shutdown() {
        scheduledExecutorService.shutdown();
    }

    @Override
    public List<Runnable> shutdownNow() {
        return scheduledExecutorService.shutdownNow();
    }

    @Override
    public boolean isShutdown() {
        return scheduledExecutorService.isShutdown();
    }

    @Override
    public boolean isTerminated() {
        return scheduledExecutorService.isTerminated();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return scheduledExecutorService.awaitTermination(timeout, unit);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return scheduledExecutorService.submit(TtlCallable.get(MDCThreadWrap.callable(task), false, idempotent));
    }

    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        return scheduledExecutorService.submit(TtlRunnable.get(MDCThreadWrap.runnable(task), false, idempotent), result);
    }

    @Override
    public Future<?> submit(Runnable task) {
        return scheduledExecutorService.submit(TtlRunnable.get(MDCThreadWrap.runnable(task), false, idempotent));

    }

    @Override
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
        return scheduledExecutorService.invokeAll(tasks);
    }

    @Override
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
        return scheduledExecutorService.invokeAll(tasks, timeout, unit);
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
        return scheduledExecutorService.invokeAny(tasks);
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return scheduledExecutorService.invokeAny(tasks, timeout, unit);
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
        return scheduledExecutorService.schedule(TtlRunnable.get(MDCThreadWrap.runnable(command)), delay, unit);
    }

    @Override
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
        return scheduledExecutorService.schedule(TtlCallable.get(MDCThreadWrap.callable(callable)), delay, unit);
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
        return scheduledExecutorService.scheduleAtFixedRate(TtlRunnable.get(MDCThreadWrap.runnable(command)), initialDelay, period, unit);
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
        return scheduledExecutorService.scheduleWithFixedDelay(TtlRunnable.get(MDCThreadWrap.runnable(command)), initialDelay, delay, unit);

    }
}
